#include <cstddef>
#include <iostream>
#include <pthread.h>
#include <unistd.h>
using namespace std;
#define QueueSize 5
#define ProudceSize 10
#define ConsumeSize 10
typedef struct {
    int buffer[QueueSize];
    int front;
    int rear;
    int count;
    pthread_mutex_t lock;
    pthread_cond_t not_full;
    pthread_cond_t not_empty;
}BlockingQueue;
void init(BlockingQueue* q) {
    pthread_mutex_init(&q->lock, nullptr);
    pthread_cond_init(&q->not_full, nullptr);
    pthread_cond_init(&q->not_empty, nullptr);
    q->front = 0;
    q->rear = 0;
    q->count = 0;
}
void Enqueue(BlockingQueue* q, int val) {
    pthread_mutex_lock(&q->lock);
    while (q->count == QueueSize) {
        pthread_cond_wait(&q->not_full, &q->lock);
    }
    q->buffer[q->rear] = val;
    q->rear = (q->rear + 1) % QueueSize;
    q->count++;
    pthread_cond_signal(&q->not_empty);
    pthread_mutex_unlock(&q->lock);
}
int Dequeue(BlockingQueue* q) {
    pthread_mutex_lock(&q->lock);
    while (q->count == 0) {
        pthread_cond_wait(&q->not_empty, &q->lock);
    }
    int val = q->buffer[q->front];
    q->front = (q->front + 1) % QueueSize;
    q->count--;
    pthread_cond_signal(&q->not_full);
    pthread_mutex_unlock(&q->lock);
    return val;
}
void* produce(void* arg) {
    BlockingQueue* q = (BlockingQueue*)arg;
    for(int i = 0; i < ProudceSize; i++) {
        cout << "生产者在生产：" << i << endl;
        Enqueue(q, i);
        sleep(1);
    }
    return nullptr;
}
void* consume(void* arg) {
    BlockingQueue* q = (BlockingQueue*)arg;
    for(int i = 0; i < ConsumeSize; i++) {
        int temp = Dequeue(q);
        cout << "消费者在消费了：" << temp << endl;
        sleep(3);
    }
    return nullptr;
}
int main() {
    BlockingQueue q;
    init(&q);
    pthread_t p, c;
    pthread_create(&p, NULL, produce, (void*)&q);
    pthread_create(&c, NULL, consume, (void*)&q);
    pthread_join(p, NULL);
    pthread_join(c, NULL);
    pthread_cond_destroy(&q.not_empty);
    pthread_cond_destroy(&q.not_full);
    pthread_mutex_destroy(&q.lock);
    return 0;
}